﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;

namespace TS2000ControlLibrary
{
    public delegate void ControlEventHandler(object source, ControlEventArgs e);
    public delegate void ReadControlOperatingModeEventHandler(object source, ControlOperatingModeEventArgs e);

    public enum OperatingMode
    {
        LSB = 1,
        USB = 2,
        CW = 3,
        FM = 4,
        AM = 5,
        FSK = 6,
        CWR = 7,
        FSKR = 9
    }

    public enum OnOff
    {
        On,
        Off
    }

    public enum Band
    {
        Band160m,
        Band80m,
        Band40m,
        Band20m,
        Band17m,
        Band15m,
        Band12m,
        Band10m,
        Band6m,
        Band2m,
        Band440
    }

    public enum OffsetShift
    {
        None,
        Plus,
        Minus

    }

    public class Control
    {
        public event ControlEventHandler OnFrequencyRead;
        public event ReadControlOperatingModeEventHandler OnModeRead;

        System.IO.Ports.SerialPort sp = null;
        private string _port = "";
        private int _baud;
        private string inBuffer = "";
        private string lastFrequency = "";
        private string lastMeter = "";
        private OperatingMode lastMode;
        private string lastTone = "";

        public Control()
        {

        }

        public string LastMeter
        {
            get { return lastMeter; }
        }

        public string LastTone
        {
            get { return lastTone; }
        }


        private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while (sp.BytesToRead > 0)
            {

                string inChar = char.ConvertFromUtf32(sp.ReadChar());

                if (inChar == ";")
                {
                    if (inBuffer == "?" || inBuffer == "E" || inBuffer == "O")
                    {
                        inBuffer = "";
                    }
                    else
                    {
                        string cmd = inBuffer.Substring(0, 2);
                        string parms = inBuffer.Substring(2);

                        switch (cmd)
                        {
                            case "FA":
                                {
                                    parms = parms.Insert(5, ".");
                                    lastFrequency = parms.TrimStart(new Char[] { '0' });
                                    inBuffer = "";
                                    OnFrequencyRead(this, new ControlEventArgs(lastFrequency));
                                    break;
                                }
                            case "SM":
                                {
                                    lastMeter = parms;
                                    inBuffer = "";
                                    break;
                                }
                            case "MD":
                                {
                                    lastMode = (OperatingMode)Enum.Parse(typeof(OperatingMode), parms);
                                    inBuffer = "";
                                    OnModeRead(this, new ControlOperatingModeEventArgs(lastMode));
                                    break;
                                }
                            case "TN":
                                {
                                    lastTone = parms;
                                    inBuffer = "";
                                    break;
                                }

                            default:
                                inBuffer = "";
                                break;
                        }
                    }
                }
                else
                    inBuffer += inChar;
            }
        }

        public void Connect(string port, int baud)
        {
            _port = port;
            _baud = baud;

            sp = new SerialPort(_port.ToString(), baud, Parity.None, 8, StopBits.One);
            sp.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
            sp.Open();
            sp.DiscardInBuffer();


        }

        public void Disconnect()
        {
            if (sp.IsOpen)
            {
                sp.Close();    
            }
            
            sp = null;
        }

        public void SetFrequency(int frequency)
        {
            string param = "00000000000";
            string freq = frequency.ToString(param);

            if (sp != null)
            {
                sp.RtsEnable = true;
                sp.WriteLine("FA" + freq + ";");
                sp.RtsEnable = false;
            }

            //RequestFrequency();
        }

        public void RequestFrequency()
        {
            if (sp != null)
            {
                sp.RtsEnable = true;
                sp.WriteLine("FA;");
                sp.RtsEnable = false;
            }
        }

        public void RequestOperatingMode()
        {
            if (sp != null)
            {
                sp.RtsEnable = true;
                sp.WriteLine("MD;");
                sp.RtsEnable = false;
            }

        }

        public void PowerOff()
        {
            if (sp != null)
            {
                sp.RtsEnable = true;
                sp.WriteLine("PS0;");
                sp.RtsEnable = false;

                this.Disconnect();
            }
        }


        public string RequestMeter()
        {
            if (sp != null)
            {
                sp.RtsEnable = true;
                sp.WriteLine("SM0;");
                sp.RtsEnable = false;
            }

            return lastMeter;
        }

        public void SetOperatingMode(OperatingMode mode)
        {
            if (sp != null)
            {
                sp.RtsEnable = true;
                sp.WriteLine("MD" + Convert.ToInt32(mode).ToString() + ";");
                sp.RtsEnable = false;
            }
        }

        public void SetToneFrequency(double frequency)
        {
            double[] freqs = new double[43]
            { 
                67.0, 69.3, 71.9, 74.4, 77.0, 79.7, 82.5, 85.4, 88.5, 91.5, 94.8,
                97.4, 100.0, 103.5, 107.2, 110.9, 114.8, 118.8, 123.0, 127.3, 131.8, 136.5,
                141.3, 146.2, 151.4, 156.7, 162.2, 167.9, 173.8, 179.9, 186.2, 192.8, 203.5,
                206.5, 210.7, 218.1, 225.7, 229.1, 233.6, 241.8, 250.3, 254.1, 1750
            };

            int freqIndex = 0;
            bool found = false;
            for (; freqIndex < freqs.Length; freqIndex++)
            {
                if (freqs[freqIndex] == frequency)
                {
                    found = true;
                    break;
                }
            }

            if (sp != null && found)
            {
                string param = "00";
                string freq = freqIndex.ToString(param);

                if (sp != null)
                {
                    sp.RtsEnable = true;
                    sp.WriteLine("TN" + freq + ";");
                    sp.RtsEnable = false;
                }
            }
        }

        public void RequestToneFrequency()
        {
            if (sp != null)
            {
                sp.RtsEnable = true;
                sp.WriteLine("TN;");
                sp.RtsEnable = false;
            }
        }

        public void SetTone(OnOff onOff)
        {
            if (sp != null)
            {
                sp.RtsEnable = true;

                if (onOff == OnOff.On)
                    sp.WriteLine("TO1;");
                else
                    sp.WriteLine("TO0;");

                sp.RtsEnable = false;
            }
        }

        public void SetBandUp()
        {
            this.SendCommand("BU;");
        }

        public void SetBandDown()
        {
            this.SendCommand("BD;");
        }

        public void SetOffsetShift(OffsetShift os)
        {
            string cmd = "OS";

            if (os == OffsetShift.None) cmd += "0";
            if (os == OffsetShift.Plus) cmd += "1";
            if (os == OffsetShift.Minus) cmd += "-";

            cmd += ";";

            SendCommand(cmd);
        }


        public void SendCommand(string cmd)
        {
            if (sp != null)
            {
                sp.RtsEnable = true;

                sp.WriteLine(cmd);

                sp.RtsEnable = false;
            }
        }
    }
}
